package tracking.service;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;

import tracking.LTEConstants;
import tracking.LogUtil;
import tracking.Utils;
import tracking.dao.DBConnection;
import tracking.dao.Trackingdao;
import tracking.dto.Detailsdto;
import tracking.dto.Devicedto;
import tracking.dto.Trackingdto;
import tracking.dto.TrafficDto;

@Path("/tracking")
public class TrackingManager {
	private static final String TAG = "TrackingManager";

	@GET
	@Path("/get")
	@Produces("application/json")
	public String get(@QueryParam("data") String data){
		
		if(data == null || data.isEmpty()){
			return userReturn(LTEConstants.STATUS_ERROR_ERROR_PARAMETER, "STATUS_ERROR_ERROR_PARAMETER");
		}
		
		try {
			Connection conn = DBConnection.getInstant().getConnection();
			if(conn == null){
				return userReturn(LTEConstants.STATUS_ERROR_CONNECT_DATABASE, "STATUS_ERROR_CONNECT_DATABASE");
			}
			LogUtil.log(TAG, "NECVN>>>get tracking " + TAG + "-" + "data:" + data);
			data = Utils.decode(data);
			Trackingdto dto = Utils.getTrackingtoFromJson(data);
			dto.setStatus(LTEConstants.STATUS_OK);
			Trackingdao dao = new Trackingdao(conn);
			int type = dto.getType();
			if(type == LTEConstants.TYPE_0){
				return userReturn(LTEConstants.STATUS_ERROR_TYPE, "STATUS_ERROR_TYPE");
			}
			
			
			ResultSet resultSet;
			String detailsId;
			int trafficSum = 0;
			ResultSet rs;
			List<TrafficDto> listTraffic = new ArrayList<TrafficDto>();
			TrafficDto trafficDto;
			List<Detailsdto> list = new ArrayList<Detailsdto>();
			Detailsdto dtoDetails;
			
			int arrange;
			
			int key;
			int value;
			switch (type) {
			case LTEConstants.TYPE_DAY:
				//TODO DAY
				LogUtil.log(TAG, "--------------------TYPE_DAY------------------------");
				resultSet = dao.getTrackingByDay(dto);
				if(resultSet == null){
					return userReturn(LTEConstants.STATUS_FAIL, "TYPE_DAY resultSet == NULL");
				}
				
				if(!resultSet.first()){
					return userReturn(LTEConstants.STATUS_FAIL, "TYPE_DAY NO data");
				}
				//list all hour
				do {
					value = 0;
					detailsId = resultSet.getString("detailsId");
					LogUtil.log(TAG, "***************detailsId:" + detailsId + "**********");
					
					rs = dao.getDetails(detailsId);
					if(rs == null || !rs.first()){
						return userReturn(LTEConstants.STATUS_FAIL, "Get details error");
					}
					do {
						String appname = rs.getString("appname");
						String packagename = rs.getString("packagename");
						int trafficDetails = rs.getInt("traffic");
						value += trafficDetails;

						Timestamp timestamp = rs.getTimestamp("lastupdate");
						timestamp.getTime();
						long longtime = timestamp.getTime();
						String time = Utils.getTime(longtime);
						LogUtil.log(TAG, "appname:" + appname + ";packagename:"
								+ packagename + ";trafficDetails:"
								+ trafficDetails + ";time:" + time);
						dtoDetails = new Detailsdto(appname, packagename,
								trafficDetails, longtime, time);
						if (!isExistAppname(list, appname, trafficDetails)) {
							LogUtil.log(TAG, "add new:" + appname);
							list.add(dtoDetails);
						}

					} while (rs.next());
					
					key = resultSet.getInt("hour");
					trafficDto = new TrafficDto(key, value);
					listTraffic.add(trafficDto);
					
					LogUtil.log(TAG, "key:" + key + ";value:" + value);
					
				} while (resultSet.next());
				
				//get trafficSUM
				for (TrafficDto d : listTraffic) {
					trafficSum += d.getValue();
				}
				
				dto.setTrafficSum(trafficSum);
				//arrange
				arrange = dto.getArrange();
				arrange(list, arrange);
				
				dto.setList(list);
				dto.setListTraffics(listTraffic);
				
				break;
			case LTEConstants.TYPE_MONTH:
				//TODO MONTH
				LogUtil.log(TAG, "--------------------TYPE_MONTH--------------------");
				resultSet = dao.getTrackingByMonth(dto);
				if(resultSet == null){
					return userReturn(LTEConstants.STATUS_FAIL, "dao.getTrackingByMonth(dto) NULL");
				}
				
				if(!resultSet.first()){
					return userReturn(LTEConstants.STATUS_FAIL, "NO data");
				}
				//list all hour
				do {
					value = 0;
					detailsId = resultSet.getString("detailsId");
					LogUtil.log(TAG, "***************detailsId:" + detailsId + "**********");
					
					rs = dao.getDetails(detailsId);
					if(rs == null || !rs.first()){
						return userReturn(LTEConstants.STATUS_FAIL, "Get details error");
					}
					do {
						String appname = rs.getString("appname");
						String packagename = rs.getString("packagename");
						int trafficDetails = rs.getInt("traffic");
						value += trafficDetails;

						Timestamp timestamp = rs.getTimestamp("lastupdate");
						timestamp.getTime();
						long longtime = timestamp.getTime();
						String time = Utils.getTime(longtime);
						LogUtil.log(TAG, "appname:" + appname + ";packagename:"
								+ packagename + ";trafficDetails:"
								+ trafficDetails + ";time:" + time);
						dtoDetails = new Detailsdto(appname, packagename,
								trafficDetails, longtime, time);
						if (!isExistAppname(list, appname, trafficDetails)) {
							LogUtil.log(TAG, "add new:" + appname);
							list.add(dtoDetails);
						}

					} while (rs.next());
					
					key = resultSet.getInt("day");
					trafficDto = new TrafficDto(key, value);
					if(!isKeyInListTraffic(listTraffic, key, value)){
						listTraffic.add(trafficDto);
					}
					
					LogUtil.log(TAG, "key:" + key + ";value:" + value);
					
				} while (resultSet.next());
				
				//get trafficSUM
				for (TrafficDto d : listTraffic) {
					trafficSum += d.getValue();
				}
				
				dto.setTrafficSum(trafficSum);
				//arrange
				arrange = dto.getArrange();
				arrange(list, arrange);
				
				dto.setList(list);
				dto.setListTraffics(listTraffic);
				break;
			case LTEConstants.TYPE_YEAR:
				//TODO YEAR
				LogUtil.log(TAG, "***************TYPE_YEAR*******************");
				resultSet = dao.getTrackingByYear(dto);
				if(resultSet == null){
					return userReturn(LTEConstants.STATUS_FAIL, "resultSet == null");
				}
				
				if(!resultSet.first()){
					return userReturn(LTEConstants.STATUS_FAIL, "NO data");
				}
				do {
					value = 0;
					detailsId = resultSet.getString("detailsId");
					LogUtil.log(TAG, "***************detailsId:" + detailsId + "**********");
					
					rs = dao.getDetails(detailsId);
					if(rs == null || !rs.first()){
						return userReturn(LTEConstants.STATUS_FAIL, "Get details error");
					}
					do {
						String appname = rs.getString("appname");
						String packagename = rs.getString("packagename");
						int trafficDetails = rs.getInt("traffic");
						value += trafficDetails;

						Timestamp timestamp = rs.getTimestamp("lastupdate");
						timestamp.getTime();
						long longtime = timestamp.getTime();
						String time = Utils.getTime(longtime);
						LogUtil.log(TAG, "appname:" + appname + ";packagename:"
								+ packagename + ";trafficDetails:"
								+ trafficDetails + ";time:" + time);
						dtoDetails = new Detailsdto(appname, packagename,
								trafficDetails, longtime, time);
						if (!isExistAppname(list, appname, trafficDetails)) {
							LogUtil.log(TAG, "add new:" + appname);
							list.add(dtoDetails);
						}

					} while (rs.next());
					
					key = resultSet.getInt("month");
					trafficDto = new TrafficDto(key, value);
					if(!isKeyInListTraffic(listTraffic, key, value)){
						listTraffic.add(trafficDto);
					}
					
					LogUtil.log(TAG, "key:" + key + ";value:" + value);
					
				} while (resultSet.next());
				
				//get trafficSUM
				for (TrafficDto d : listTraffic) {
					trafficSum += d.getValue();
				}
				
				dto.setTrafficSum(trafficSum);
				//arrange
				arrange = dto.getArrange();
				arrange(list, arrange);
				
				dto.setList(list);
				dto.setListTraffics(listTraffic);
				break;
			case LTEConstants.TYPE_DAY_TO_DAY:
				//TODO TYPE_LAST_7_DAYS
				LogUtil.log(TAG, "***************TYPE_DAY_TO_DAY*******************");
				resultSet = dao.getTrackingByDayToDay(dto);
				if(resultSet == null){
					return userReturn(LTEConstants.STATUS_FAIL, "TYPE_DAY_TO_DAY resultSet == NULL");
				}
				
				if(!resultSet.first()){
					return userReturn(LTEConstants.STATUS_FAIL, "TYPE_DAY_TO_DAY NO data");
				}
				//list all hour
				do {
					value = 0;
					detailsId = resultSet.getString("detailsId");
					LogUtil.log(TAG, "***************detailsId:" + detailsId + "**********");
					
					rs = dao.getDetails(detailsId);
					if(rs == null || !rs.first()){
						return userReturn(LTEConstants.STATUS_FAIL, "Get details error");
					}
					do {
						String appname = rs.getString("appname");
						String packagename = rs.getString("packagename");
						int trafficDetails = rs.getInt("traffic");
						value += trafficDetails;

						Timestamp timestamp = rs.getTimestamp("lastupdate");
						timestamp.getTime();
						long longtime = timestamp.getTime();
						String time = Utils.getTime(longtime);
						LogUtil.log(TAG, "appname:" + appname + ";packagename:"
								+ packagename + ";trafficDetails:"
								+ trafficDetails + ";time:" + time);
						dtoDetails = new Detailsdto(appname, packagename,
								trafficDetails, longtime, time);
						if (!isExistAppname(list, appname, trafficDetails)) {
							LogUtil.log(TAG, "add new:" + appname);
							list.add(dtoDetails);
						}

					} while (rs.next());
					
					key = resultSet.getInt("day");
					if(!isKeyInListTraffic(listTraffic, key, value)){
						int month = resultSet.getInt("month");
						int year = resultSet.getInt("year");
						trafficDto = new TrafficDto(key, value);
						trafficDto.setNotes(" " + key + "/" + month + "/" + year);
						listTraffic.add(trafficDto);
					}
					
					LogUtil.log(TAG, "key:" + key + ";value:" + value);
					
				} while (resultSet.next());
				
				//get trafficSUM
				for (TrafficDto d : listTraffic) {
					trafficSum += d.getValue();
				}
				
				dto.setTrafficSum(trafficSum);
				//arrange
				arrange = dto.getArrange();
				arrange(list, arrange);
				
				dto.setList(list);
				dto.setListTraffics(listTraffic);
				break;
			case LTEConstants.TYPE_LAST_MONTH:
				//TODO TYPE_LAST_MONTH
				LogUtil.log(TAG, "***************TYPE_LAST_MONTH*******************");
				
				break;
			default:
				break;
			}
			LogUtil.log(TAG, ">>>GET SUCCESSFULL>>>>>>>>>>>>:" + dto.getDeviceId());
			return Utils.getStringFromTrackingdto(dto);
		} catch (Exception e) {
			LogUtil.log(TAG, "error tracking get:" + e.toString());
			return userReturn(LTEConstants.STATUS_FAIL,"exception:" + e.toString());
			

		}
	}

	public void arrange(List<Detailsdto> list, int arrange) {
		if(arrange == LTEConstants.ARRANGE_YES){
			LogUtil.log(TAG, "sort traffic");
			Collections.sort(list, new Comparator<Detailsdto>() {

				@Override
				public int compare(Detailsdto o1, Detailsdto o2) {
					if(o1.getTraffic() >= o2.getTraffic()){
						return -1;
					}
					return 1;
				}
				
			});
		}else{
			LogUtil.log(TAG, "sort day");
			Collections.sort(list, new Comparator<Detailsdto>() {

				@Override
				public int compare(Detailsdto o1, Detailsdto o2) {
					if(o1.getLongtime() >= o2.getLongtime()){
						return -1;
					}
					return 1;
				}
				
			});
		}
	}
	
	public String userReturn(int status, String message){
		LogUtil.log(TAG, "userReturn:" + status + ";message:" + message);
		Trackingdto dto = new Trackingdto();
		dto.setStatus(status);
		dto.setMessage(message);
		return Utils.getString(dto);
	}
	
	public boolean isExistAppname(List<Detailsdto> list, String appname, int traffic){
		if(list == null || list.size() == 0){
			LogUtil.log(TAG, "list null 0");
			return false;
		}
		for (Detailsdto dto : list) {
			if(appname.equalsIgnoreCase(dto.getAppname())){
				int currentTraffic = dto.getTraffic();
				int newtraffic = currentTraffic + traffic;
				dto.setTraffic(newtraffic);
				LogUtil.log(TAG, "appname:" + appname + " ;currentTraffic:" + currentTraffic + ";newtraffic:" + newtraffic);
				return true;
			}
		}
		return false;
	}
	
	public boolean isExistAppname(List<Detailsdto> list, Detailsdto d, int traffic){
		if(list == null || list.size() == 0){
			LogUtil.log(TAG, "list null 0");
			return false;
		}
		String appname = d.getAppname();
		long current = d.getLongtime();
		String time = d.getTime();
		
		for (Detailsdto dto : list) {
			if(appname.equalsIgnoreCase(dto.getAppname())){
				int currentTraffic = dto.getTraffic();
				int newtraffic = currentTraffic + traffic;
				dto.setTraffic(newtraffic);
				if(dto.getLongtime() < current){
					dto.setLongtime(current);
					dto.setTime(time);
				}
				LogUtil.log(TAG, "appname:" + appname + " ;currentTraffic:" + currentTraffic + ";newtraffic:" + newtraffic);
				return true;
			}
		}
		return false;
	}
	
	@GET
	@Path("/device")
	@Produces("application/json")
	public String getDivice(@QueryParam("data") String data){
		
		if(data == null || data.isEmpty()){
			return userReturn(LTEConstants.STATUS_FAIL, "data is null");
		}
		
		try {
			Connection conn = DBConnection.getInstant().getConnection();
			if(conn == null){
				return userReturn(LTEConstants.STATUS_FAIL, "connection error");
			}
			data = Utils.decode(data);
			System.out.println("NECVN>>>getDivice" + TAG + "-" + "data:" + data);
			Trackingdao dao = new Trackingdao(conn);
			ResultSet resultSet = dao.getDeviceId(data);
			if(resultSet == null || !resultSet.first()){
				return userReturn(LTEConstants.STATUS_FAIL, "Don't find any divice with user:" + data);
			}
			List<String>listDevice = new ArrayList<String>();
			do {
				String deviceId = resultSet.getString("deviceid");
				listDevice.add(deviceId);
			} while (resultSet.next());
			Devicedto dto = new Devicedto(listDevice);
			
			resultSet.close();
			LogUtil.log(TAG, "======get success==========");
			return Utils.getStringFromDevicedto(dto);

		} catch (Exception e) {
			return userReturn(LTEConstants.STATUS_FAIL,"exception:" + e.toString());
			

		}
	}
	
	@GET
	@Path("/set")
	@Produces("application/json")
	public String setdata(@QueryParam("data") String data){
		LogUtil.log(TAG, "*******************SET********************");
		if(data == null || data.isEmpty()){
			return userReturn(LTEConstants.STATUS_ERROR_ERROR_PARAMETER, "STATUS_ERROR_ERROR_PARAMETER");
		}
		try {
			Connection conn = DBConnection.getInstant().getConnection();
			if(conn == null){
				return userReturn(LTEConstants.STATUS_ERROR_CONNECT_DATABASE, "STATUS_ERROR_CONNECT_DATABASE");
			}
			data = Utils.decode(data);
			System.out.println("NECVN>>>set data" + TAG + "-" + "data:" + data);
			Trackingdao dao = new Trackingdao(conn);
			Trackingdto dto = Utils.getTrackingtoFromJson(data);
			
			int i = dao.insertDetails(dto);
			LogUtil.log(TAG, "inser details:" + i);
			if(i == -1){
				return userReturn(LTEConstants.STATUS_FAIL, "error dao.insertDetails");
			}
			
			List<Detailsdto> listDetailsdtos = dto.getList();
			for (Detailsdto detailsdto : listDetailsdtos) {
				
				int i1 = dao.insertTracking2(dto, detailsdto);
				
				if(i1 == -1){
					return userReturn(LTEConstants.STATUS_FAIL, "error dao.insertTracking");
				}
				LogUtil.log(TAG, "insert success to tracking:" + detailsdto.getLongtime());
			}
			LogUtil.log(TAG, "======insert success==========");
			return userReturn(LTEConstants.STATUS_OK, "insert success");

		} catch (Exception e) {
			return userReturn(LTEConstants.STATUS_FAIL,"exception set:" + e.toString());
		}
	}
	
	@GET
	@Path("/wet")
	@Produces("application/json")
	public String setdataw(@QueryParam("data") String data){
		LogUtil.log(TAG, "*******************SET********************");
		if(data == null || data.isEmpty()){
			return userReturn(LTEConstants.STATUS_ERROR_ERROR_PARAMETER, "STATUS_ERROR_ERROR_PARAMETER");
		}
		try {
			Connection conn = DBConnection.getInstant().getConnection();
			if(conn == null){
				return userReturn(LTEConstants.STATUS_ERROR_CONNECT_DATABASE, "STATUS_ERROR_CONNECT_DATABASE");
			}
			data = Utils.decode(data);
			System.out.println("NECVN>>>set data" + TAG + "-" + "data:" + data);
			Trackingdao dao = new Trackingdao(conn);
			Trackingdto dto = Utils.getTrackingtoFromJson(data);
			
			int i = dao.insertDetails(dto);
			LogUtil.log(TAG, "inser details:" + i);
			if(i == -1){
				return userReturn(LTEConstants.STATUS_FAIL, "error dao.insertDetails");
			}
			
			List<Detailsdto> listDetailsdtos = dto.getList();
			for (Detailsdto detailsdto : listDetailsdtos) {
				
				int i1 = dao.insertTracking2(dto, detailsdto);
				
				if(i1 == -1){
					return userReturn(LTEConstants.STATUS_FAIL, "error dao.insertTracking");
				}
				LogUtil.log(TAG, "insert success to tracking:" + detailsdto.getLongtime());
			}
			LogUtil.log(TAG, "======insert success==========");
			return userReturn(LTEConstants.STATUS_OK, "insert success");

		} catch (Exception e) {
			return userReturn(LTEConstants.STATUS_FAIL,"exception set:" + e.toString());
		}
	}
	
	public boolean isKeyInListTraffic(List<TrafficDto> list, int key, int value){
		for (TrafficDto trafficDto : list) {
			if(key == trafficDto.getKey()){
				trafficDto.setValue(value +  trafficDto.getValue());
				return true;
				
			}
		}
		return false;
	}
	
	
}
